#pragma once
#include <ostream>
#include <memory>
#include <vector>
#include <sstream>
#include <tuple>
#include "message.hpp"
#include "loglevel.hpp"
/*    该模块用来设计格式化输出
    [%d{%H:%M:%S}][%c][%p][%f][%l][%t][%T][%n][%m]
        子格式化:继承基类:重写基类的接口 不同的类型调用不同的类(ostream,value)
    Formatter:
        解析字符串，将结果放到_format数组中
        需要的接口:
            string-format()  os void format() 往流或者返回字符串
            parsePatten(读取% ->不是则为(%% ,a)，构造普通k-v)
                是% 读取下一个d判断{ }
                   or 无{} 放k -v
            继续读取下一个
*/

namespace ns_logger
{
    class FormatItem
    {
    public:
        virtual ~FormatItem() {}
        virtual void format(std::ostream &os, const LogMsg &msg) = 0;
    };
    using PSS = std::pair<std::string, std::string>;
    using FormatItemPtr = std::shared_ptr<FormatItem>;

    // 时间、等级、线程id、文件名、行号、日志器名称、body
    class TimeFormatItem : public FormatItem
    {
    public:
        TimeFormatItem(const std::string &form = "%H:%M:%S")
            : _format(form)
        {
            if(_format.empty())
                _format="%H:%M:%S";
        }
        void format(std::ostream &os, const LogMsg &msg) override
        {
            time_t t =msg._time;
            struct tm tm;
            localtime_r(&t, &tm);
            char tmp[128];
            strftime(tmp, 127,_format.c_str(), &tm);
            os<<tmp;
        }

    private:
        std::string _format;
    };
    // 等级
    class ClassFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << LogLevel::LevelToString(msg._level);
        }
    };

    // 线程id
    class TidFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._tid;
        }
    };

    // 文件名
    class FileFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._file;
        }
    };

    // 行号
    class LineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._line;
        }
    };

    // 日志器名称
    class NameFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._name;
        }
    };
    // body
    class BodyFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << msg._payload;
        }
    };
    class NFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << "\n";
        }
    };

    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string &str)
            : _str(str)
        {
        }
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << _str;
        }

    private:
        std::string _str;
    };

    class TFormatItem : public FormatItem
    {
    public:
        void format(std::ostream &os, const LogMsg &msg) override
        {
            os << "\t";
        }
    };

    // 接收消息，并且把子格式化器组织到iter数组中
    class Formatter
    {
    public:
        Formatter(const std::string &patten = "[%p][%d{%H:%M:%S}][%c][%t][%f][%l]%T %m %n")
            : _patten(patten)
        {
            if (!parsePatten())
            {
                exit(-1);
                std::cout << "parse:" << patten << "error" << std::endl;
            }
        }
        std::string format(const LogMsg &msg)
        {
            std::stringstream ss;
            for (auto& item : _item)
            {
                item->format(ss, msg);
            }
            return ss.str();
        }

        std::ostream& format (std::ostream &os, const LogMsg &msg)
        {
            for (auto &item : _item)
                item->format(os, msg);
            return os;
        }

    private:
        // 时间、等级、线程id、文件名、行号、日志器名称、body
        FormatItemPtr GetItem(const std::string &ch, const std::string &value)
        {
            if (ch == "d")
                return std::make_shared<TimeFormatItem>(value);
            else if (ch == "p")
                return std::make_shared<ClassFormatItem>();
            else if (ch == "t")
                return std::make_shared<TidFormatItem>();
            else if (ch == "f")
                return std::make_shared<FileFormatItem>();
            else if (ch == "l")
                return std::make_shared<LineFormatItem>();
            else if (ch == "c")
                return std::make_shared<NameFormatItem>();
            else if (ch == "m")
                return std::make_shared<BodyFormatItem>();
            else if (ch == "T")
                return std::make_shared<TFormatItem>();
            else if (ch == "n")
                return std::make_shared<NFormatItem>();
            if(value!="")
                return std::make_shared<OtherFormatItem>(value);
            std::cout<<"没有对应的格式化选项:%"<<ch<<std::endl;
            abort();
            return  FormatItemPtr();
        }

        bool parsePatten()
        {
            int pos = 0;
            std::vector<PSS> ret;
            while (pos < _patten.size())
            {
                std::string key, val;
                // 普通字符
                if (_patten[pos] != '%')
                {
                    ret.push_back(std::make_pair(key, std::string(1, _patten[pos])));
                    ++pos;
                    continue;
                }
                ++pos;
                // %%
                if (pos < _patten.size() && _patten[pos] == '%')
                {
                    ret.push_back(std::make_pair(key, std::string(1, _patten[pos])));
                    ++pos;
                    continue;
                }

                // 到这里就是%d{} %p的形式
                key += _patten[pos];
                pos++;
                if (_patten[pos] == '{')
                {
                    ++pos;
                    // 不加入左括号
                    while (pos < _patten.size() && _patten[pos] != '}')
                    {
                        val += _patten[pos++];
                    }
                    if (_patten[pos] != '}')
                    {
                        std::cout << "没有匹配的}" << std::endl;
                        return false;
                    }
                    ++pos;
                }
                ret.push_back(std::make_pair(key, val));
            }
            //Debug 用来观察数据的切分
            // for (auto &it : ret)
            // {
            //     if (std::get<0>(it) != "")
            //         std::cout << " key:" << std::get<0>(it) << " ";
            //     if (std::get<1>(it) != "")
            //         std::cout << " val:" << std::get<1>(it) << " ";
            //     std::cout << std::endl;
            // }
            // 遍历ret,创建子格式化
            for (auto &it : ret)
            {
                // 创建子格式化
                if (std::get<0>(it) == "")
                {
                    FormatItemPtr fi(new OtherFormatItem(std::get<1>(it)));
                    _item.push_back(fi);
                }
                else if (std::get<0>(it) != "" && std::get<1>(it) == "")
                {
                    FormatItemPtr fi = GetItem(std::get<0>(it), std::string());
                    _item.push_back(fi);
                }
                else
                {
                    FormatItemPtr fi = GetItem(std::get<0>(it), std::get<1>(it));
                    _item.push_back(fi);
                }
            }
            return true;
        }

    private:
        std::string _patten;
        std::vector<FormatItemPtr> _item;
    };

    using FormatterPtr=std::shared_ptr<Formatter>;

};